package com.wave.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wave.common.core.domain.PageQuery;
import com.wave.common.core.page.TableDataInfo;
import com.wave.common.exception.ServiceException;
import com.wave.common.utils.StringUtils;
import com.wave.common.utils.redis.RedisUtils;
import com.wave.system.domain.*;
import com.wave.system.domain.bo.SysToolBoardTaskBo;
import com.wave.system.domain.vo.SysToolBoardTaskVo;
import com.wave.system.mapper.SysProductConfigMapper;
import com.wave.system.mapper.SysToolBoardLineMapper;
import com.wave.system.mapper.SysToolBoardTaskMapper;
import com.wave.system.mapper.SysToolShelfTaskMapper;
import com.wave.system.service.ISysProduceArrangeService;
import com.wave.system.service.ISysProductQueryService;
import com.wave.system.service.ISysToolBoardTaskService;
import com.wave.system.util.Modbus4jUtils;
import com.wave.system.util.SnCodeConvertUtil;
import com.wave.system.util.StringSplitUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 工装板任务Service业务层处理
 *
 * @author wave
 * @date 2024-10-12
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysToolBoardTaskServiceImpl implements ISysToolBoardTaskService {

    private final SysToolBoardTaskMapper baseMapper;

    private final SysToolShelfTaskMapper toolShelfTaskMapper;

    private final SysToolBoardLineMapper toolBoardLineMapper;

    private final SysProductConfigMapper sysProductConfigMapper;

    private final ISysProductQueryService productQueryService;

    private final ISysProduceArrangeService produceArrangeService;


    /**
     * 查询工装板任务
     */
    @Override
    public SysToolBoardTaskVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询工装板任务列表
     */
    @Override
    public TableDataInfo<SysToolBoardTaskVo> queryPageList(SysToolBoardTaskBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysToolBoardTask> lqw = buildQueryWrapper(bo);
        Page<SysToolBoardTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询工装板任务列表
     */
    @Override
    public List<SysToolBoardTaskVo> queryList(SysToolBoardTaskBo bo) {
        LambdaQueryWrapper<SysToolBoardTask> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysToolBoardTask> buildQueryWrapper(SysToolBoardTaskBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysToolBoardTask> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getProductSn()), SysToolBoardTask::getProductSn, bo.getProductSn());
        lqw.like(StringUtils.isNotBlank(bo.getTargetExport()), SysToolBoardTask::getTargetExport, bo.getTargetExport());
        lqw.eq(StringUtils.isNotBlank(bo.getPathPoint1()), SysToolBoardTask::getPathPoint1, bo.getPathPoint1());
        lqw.eq(StringUtils.isNotBlank(bo.getPathPoint2()), SysToolBoardTask::getPathPoint2, bo.getPathPoint2());
        lqw.eq(StringUtils.isNotBlank(bo.getPathPoint3()), SysToolBoardTask::getPathPoint3, bo.getPathPoint3());
        lqw.notIn(SysToolBoardTask::getTaskStatus, "抓取完成", "手动完成", "CCD拍照失败");
        lqw.like(StringUtils.isNotBlank(bo.getTaskStatus()), SysToolBoardTask::getTaskStatus, bo.getTaskStatus());
        lqw.gt(params.get("beginTime") != null, SysToolBoardTask::getCreateTime, params.get("beginTime"));
        lqw.lt(params.get("endTime")!=null, SysToolBoardTask::getCreateTime, params.get("endTime"));
        lqw.orderByDesc(SysToolBoardTask::getUpdateTime);
        return lqw;
    }

    /**
     * 新增工装板任务
     */
    @Override
    public Boolean insertByBo(SysToolBoardTaskBo bo) {
        SysToolBoardTask add = BeanUtil.toBean(bo, SysToolBoardTask.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改工装板任务
     */
    @Override
    @Transactional
    public Boolean updateByBo(SysToolBoardTaskBo bo) {
        SysToolBoardTask update = BeanUtil.toBean(bo, SysToolBoardTask.class);
        validEntityBeforeSave(update);
        if ("手动完成".equals(bo.getTaskStatus())) {
            log.info("物料码:{}收到手动完成指令", bo.getProductSn());
            Integer packageLine = update.getPackageLine();
            LambdaQueryWrapper<SysToolShelfTask> queryWrapper = Wrappers.lambdaQuery(SysToolShelfTask.class)
                .eq(SysToolShelfTask::getPackageLine, packageLine)
                .ne(SysToolShelfTask::getTaskStatus, "放行完成");
            SysToolShelfTask sysToolShelfTask = toolShelfTaskMapper.selectOne(queryWrapper);
            if (ObjectUtil.isEmpty(sysToolShelfTask)) {
                throw new ServiceException("A" + packageLine + "线工装架任务不存在!");
            }
            String currentProductNumber = SnCodeConvertUtil.getProductCodeBySnCode(update.getProductSn());
            String productNumber = sysToolShelfTask.getProductNumber();
            if (StringUtils.isNotEmpty(productNumber) && !productNumber.equals(currentProductNumber)) {
                throw new ServiceException("物料型号不一致，请重新选择包装线!");
            }
            List<String> snCodes = RedisUtils.getCacheObject(sysToolShelfTask.getShelfNumber());
            if (!CollectionUtils.isEmpty(snCodes)) {
                if (snCodes.size() >= 6) {
                    throw new ServiceException("A" + packageLine + "线工装架已放满6个物料, 请重新选择!");
                }
                String snCode = snCodes.get(0);
                SysProductConfig sysProductConfig = sysProductConfigMapper.selectOne(Wrappers.lambdaQuery(SysProductConfig.class)
                    .eq(SysProductConfig::getProductNumber, productNumber));
                if (!ObjectUtil.isEmpty(sysProductConfig) && sysProductConfig.getCheckVersion() == 0) {
                    String completeVersion = produceArrangeService.checkPackInfoBySnCode(snCode);
                    String currentVersion = produceArrangeService.checkPackInfoBySnCode(update.getProductSn());
                    if (StringUtils.isNotEmpty(currentVersion) && !currentVersion.equals(completeVersion)) {
                        throw new ServiceException("物料芯片版本不一致，请重新选择包装线!");
                    }
                }
            } else {
                snCodes = new ArrayList<>();
            }
            snCodes.add(update.getProductSn());
            RedisUtils.setCacheObject(sysToolShelfTask.getShelfNumber(), snCodes);
            sysToolShelfTask.setTaskStatus("抓取" + snCodes.size() + "个产品");
            toolShelfTaskMapper.updateById(sysToolShelfTask);
            productQueryService.updateTaskQueryInfo(bo.getProductSn(), bo.getTaskStatus(), sysToolShelfTask.getShelfNumber(), 1);
            produceArrangeService.pushMesCheck(packageLine, 0);
            this.checkRedisHasCacheSnCode(update.getProductSn());
            return baseMapper.updateById(update) > 0;
        }
        return false;
    }

    private void checkRedisHasCacheSnCode(String productSn) {
        for (int i = 1; i <= 4; i++) {
            String redisKey = "A" + i + "_CURRENT_SN_CODE";
            String cacheObject = RedisUtils.getCacheObject(redisKey);
            if (StringUtils.isNotEmpty(cacheObject) && cacheObject.equals(productSn)) {
                log.info("手动完成工装板任务:{},删除CCD拍照缓存的Redis信息，redisKey:{}", productSn, redisKey);
                RedisUtils.deleteObject(redisKey);
            }
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysToolBoardTask entity) {

    }

    /**
     * 批量删除工装板任务
     */
    @Override
    @Transactional
    public Boolean deleteWithValidByIds(List<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        Long id = ids.get(0);
        SysToolBoardTask sysToolBoardTask = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(sysToolBoardTask)) {
            return false;
        }
        //productQueryService.deleteQueryInfoBySnCode(sysToolBoardTask.getProductSn());
        return baseMapper.deleteBatchIds(ids) > 0;
    }


    @Override
    public void updateToolBoardInfo(String result, Map<Integer, String> map) {
        List<String> list = null;
        try {
            list = StringSplitUtil.splitStr(result);
        } catch (Exception e) {
            log.error("更新路劲点位信息是，读取plc的sn码存在问题：{}", e.getMessage());
            list = new ArrayList<>();
        }
        if (!CollectionUtils.isEmpty(list)) {
            for (int i = 0; i < list.size(); i++) {
                String lineNode = map.get(i);//点位
                String snCode = list.get(i);//产品sn码
                if (StringUtils.isEmpty(snCode)) {
                    SysToolBoardLine sysToolBoardLine = toolBoardLineMapper.selectOne(Wrappers.lambdaQuery(SysToolBoardLine.class).eq(SysToolBoardLine::getLineNode, lineNode));
                    if (ObjectUtil.isNotEmpty(sysToolBoardLine) && StringUtils.isNotEmpty(sysToolBoardLine.getProductSn())) {
                        LambdaUpdateWrapper<SysToolBoardLine> clearWrapper = new LambdaUpdateWrapper<>();
                        clearWrapper.set(SysToolBoardLine::getProductSn, "");
                        clearWrapper.set(SysToolBoardLine::getTargetNode1, 0);
                        clearWrapper.set(SysToolBoardLine::getTargetNode2, 0);
                        clearWrapper.set(SysToolBoardLine::getUpdateTime, new Date());
                        clearWrapper.eq(SysToolBoardLine::getLineNode, lineNode);
                        toolBoardLineMapper.update(clearWrapper);
                    }
                } else {
                    SysToolBoardTask sysToolBoardTask = baseMapper.selectOne(Wrappers.lambdaQuery(SysToolBoardTask.class)
                        .eq(SysToolBoardTask::getProductSn, snCode)
                        .notIn(SysToolBoardTask::getTaskStatus, "抓取完成", "到位终点位待抓取", "手动完成"));
                    if (ObjectUtil.isEmpty(sysToolBoardTask)) {
                        continue;
                    }
                    String currentCacheBit = lineNode.substring(1, 2);
                    String targetCacheBit = sysToolBoardTask.getTargetExport().substring(1, 2);
                    if (!currentCacheBit.equals(targetCacheBit)) {
                        continue;
                    }
                    LambdaUpdateWrapper<SysToolBoardLine> wrapper = new LambdaUpdateWrapper<>();
                    String lastPointBit = lineNode.substring(3);
                    boolean needUpdate = false;
                    if ("1".equals(lastPointBit) && "0".equals(sysToolBoardTask.getPathPoint1())) {
                        sysToolBoardTask.setPathPoint1(lineNode);
                        sysToolBoardTask.setTaskStatus("到位" + lineNode);
                        wrapper.set(SysToolBoardLine::getTargetNode1, Integer.parseInt(lineNode) + 1);
                        needUpdate = true;
                    } else if ("2".equals(lastPointBit) && "0".equals(sysToolBoardTask.getPathPoint2())) {
                        sysToolBoardTask.setPathPoint2(lineNode);
                        sysToolBoardTask.setTaskStatus("到位" + lineNode);
                        wrapper.set(SysToolBoardLine::getTargetNode1, Integer.parseInt(lineNode) + 1);
                        needUpdate = true;
                    } else if ("3".equals(lastPointBit) && "0".equals(sysToolBoardTask.getPathPoint3())) {
                        sysToolBoardTask.setPathPoint3(lineNode);
                        sysToolBoardTask.setTaskStatus("到位终点位待抓取");
                        wrapper.set(SysToolBoardLine::getTargetNode1, lineNode);
                        needUpdate = true;
                    }
                    if (needUpdate) {
                        //更新工装板任务信息
                        log.info("更新工装板任务:{}状态为:{}", sysToolBoardTask.getProductSn(), sysToolBoardTask.getTaskStatus());
                        sysToolBoardTask.setUpdateTime(new Date());
                        baseMapper.updateById(sysToolBoardTask);
                        //更新工装板线体信息
                        log.info("更新工装板线体:{}的SN码为:{}", lineNode, snCode);
                        wrapper.set(SysToolBoardLine::getProductSn, snCode);
                        wrapper.set(SysToolBoardLine::getTargetNode2, 1);
                        wrapper.set(SysToolBoardLine::getUpdateTime, new Date());
                        wrapper.eq(SysToolBoardLine::getLineNode, lineNode);
                        toolBoardLineMapper.update(wrapper);
                    }
                }
            }
        }
    }


    @Override
    public Boolean repeatScanCode(Long id) {
        SysToolBoardTask sysToolBoardTask = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(sysToolBoardTask)) {
            throw new ServiceException("工装板任务不存在!");
        }
        Boolean autoRun = Modbus4jUtils.readCoilStatus(1, 4968);
        if (!autoRun) {
            throw new ServiceException("PLC程序不处于自动运行中,请稍后再试!");
        }
        log.info("物料码:{}收到重新扫码指令", sysToolBoardTask.getProductSn());
        return Modbus4jUtils.writeCoil(1, 4912, true);
    }

    @Override
    public Boolean repeatCode(Long id, String str) {
        SysToolBoardTask sysToolBoardTask = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(sysToolBoardTask)) {
            throw new ServiceException("工装板任务不存在!");
        }
        Boolean autoRun = Modbus4jUtils.readCoilStatus(1, 4968);
        if (!autoRun) {
            throw new ServiceException("PLC程序不处于自动运行中,请稍后再试!");
        }
        log.info("物料码:{}收到{}指令", sysToolBoardTask.getProductSn(), str);

        if("ok".equals(str)){
            return Modbus4jUtils.writeCoil(1, 4912, true);
        }
        if("ng".equals(str)){
            return Modbus4jUtils.writeCoil(1, 4009, true);
        }
        return false;
    }
}
